package com.jumi.microservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jumi.microservice.common.constant.RequestConstant;
import com.jumi.microservice.constant.ExceptionEnum;
import com.jumi.microservice.constant.StatusEnum;
import com.jumi.microservice.domain.Account;
import com.jumi.microservice.domain.Department;
import com.jumi.microservice.domain.dto.DepartmentDTO;
import com.jumi.microservice.domain.temp.DepartmentTemp;
import com.jumi.microservice.domain.vo.DepartmentQuery;
import com.jumi.microservice.domain.vo.DepartmentRequest;
import com.jumi.microservice.domain.vo.DepartmentVO;
import com.jumi.microservice.mapper.AccountMapper;
import com.jumi.microservice.mapper.DepartmentMapper;
import com.jumi.microservice.service.DepartmentService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 部门表 服务实现类
 * </p>
 *
 * @author liuz
 * @since 2020-07-18
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {

    /**
     * 账号管理mapper组件
     */
    @Resource
    private AccountMapper accountMapper;

    @Resource
    private DepartmentMapper departmentMapper;

    @Override
    public void insert(DepartmentDTO dto, HttpServletRequest request) {
        //判断传过来的数据是否为空
        ExceptionEnum.FAIL_NULL.doThrowIf(dto == null);
        //如果没有传父级id,默认1(主部门id)
        if (dto.getParentId() == null || dto.getParentId() == 0) {
            dto.setParentId(1L);
        }
        //部门同级名字不能重复
        int departmentNameCount = baseMapper.selectCount(
                Wrappers.<Department>lambdaQuery()
                        .eq(Department::getParentId, dto.getParentId())
                        .eq(Department::getDepartmentName, dto.getDepartmentName())
                        .eq(Department::getIsDel, StatusEnum.STATUS_NO.getCode())
        );
        ExceptionEnum.FAIL_DEPARTMENT_NAME.doThrowIf(departmentNameCount > 0);
        Department department = dto2Po(dto);
        department.setCreater(request.getHeader(RequestConstant.ADMIN_NAME));
        department.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
        //保存部门信息
        baseMapper.insert(department);
    }

    @Override
    public void update(DepartmentDTO dto, HttpServletRequest request) {
        //判断传过来的数据是否为空
        ExceptionEnum.FAIL_NULL.doThrowIf(dto == null);
        //判断传过的的id是否是空
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(dto.getId() == null);
        //判断传过来id是否能查到信息
        Department dep = baseMapper.selectById(dto.getId());
        ExceptionEnum.FAIL_NULL.doThrowIf(dep == null);
        //部门同级名字不能重复
        int departmentNameCount = baseMapper.selectCount(
                Wrappers.<Department>lambdaQuery()
                        .ne(Department::getId, dep.getId())
                        .eq(Department::getParentId, dep.getParentId())
                        .eq(Department::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .eq(Department::getDepartmentName, dto.getDepartmentName())
        );
        dto.setParentId(dep.getParentId());
        ExceptionEnum.FAIL_DEPARTMENT_NAME.doThrowIf(departmentNameCount > 0);
        Department r = dto2Po(dto);
        r.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
        baseMapper.updateById(r);
    }


    @Override
    public void delete(Long id, HttpServletRequest request) {
        //判断传过来的数据是否为空
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id == null);
        //判断传过来id是否能查到信息
        Department dep = baseMapper.selectById(id);
        ExceptionEnum.FAIL_NULL.doThrowIf(dep == null);
        //根目录不能删除
        ExceptionEnum.FAIL_DEPARTMENT_DEL1.doThrowIf(dep.getParentId() == 0);
        //启用状态下的部门，不能删除
        ExceptionEnum.FAIL_DEPARTMENT_DEL2.doThrowIf(dep.getStatus() == StatusEnum.STATUS_YES.getCode());
        //该部门下有下级部门，不能删除
        int sonCount = baseMapper.selectCount(
                Wrappers.<Department>lambdaQuery()
                        .eq(Department::getParentId, dep.getId())
                        .eq(Department::getIsDel, StatusEnum.STATUS_NO.getCode())
        );
        ExceptionEnum.FAIL_DEPARTMENT_DEL3.doThrowIf(sonCount > 0);
        //该部门下有账号关联不能删除
        int acCount = accountMapper.selectCount(
                Wrappers.<Account>lambdaQuery()
                        .eq(Account::getDepartmentId, dep.getId())
                        .eq(Account::getIsDel, StatusEnum.STATUS_NO.getCode())
        );
        ExceptionEnum.FAIL_DEPARTMENT_DEL4.doThrowIf(acCount > 0);
        dep.setIsDel(StatusEnum.STATUS_YES.getCode());
        dep.setModifier(request.getHeader(RequestConstant.ADMIN_NAME));
        baseMapper.updateById(dep);
    }

    @Override
    public void enableStatus(Long id, Integer status, HttpServletRequest request) {
        //判断传过来的数据是否为空
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id == null);
        //判断传过来id是否能查到信息
        Department dep = baseMapper.selectById(id);
        ExceptionEnum.FAIL_NULL.doThrowIf(dep == null);
        if (status == 0) {
            /**
             * 禁用 父级禁用子部门全部禁用
             */
            //获取所有子部门ID
            List<Long> sonId = baseMapper.getSonDepartment(id);
            sonId.add(id);
            //判断部门是否有绑定账户,有绑定账户不能禁用
            int account = accountMapper.selectCount(
                    Wrappers.<Account>lambdaQuery()
                            .in(Account::getDepartmentId, sonId)
                            .eq(Account::getIsDel, StatusEnum.STATUS_NO.getCode())
            );
            ExceptionEnum.FAIL_DEPARTMENT_STATUS.doThrowIf(account > 0);
            DepartmentTemp temp = new DepartmentTemp();
            temp.setSonId(sonId);
            temp.setStatus(status);
            //批量更新部门状态
            baseMapper.updateSonDepartmentStatus(temp);
        } else if (status == 1) {
            //启用 子级启用父级全部启用
            List<Long> sonId = baseMapper.getFatherDepartment(id);
            DepartmentTemp temp = new DepartmentTemp();
            temp.setSonId(sonId);
            temp.setStatus(status);
            //批量更新部门状态\
            baseMapper.updateSonDepartmentStatus(temp);
        }
    }

    @Override
    public DepartmentDTO selectById(Long id) {
        ExceptionEnum.FAIL_ID_NULL.doThrowIf(id == null);
        Department dep = baseMapper.selectById(id);
        ExceptionEnum.FAIL_NULL.doThrowIf(dep == null);
        DepartmentDTO departmentDTO = po2Dto(dep);
        return departmentDTO;
    }


    /**
     * 根据父菜单获取子菜单
     *
     * @param query
     */
    private void getChildren(DepartmentQuery query) {
        //获取当前的子菜单
        List<Department> list = baseMapper.selectList(
                Wrappers.<Department>lambdaQuery()
                        .eq(Department::getParentId, query.getId())
                        .eq(Department::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .eq(Department::getStatus,StatusEnum.STATUS_YES.getCode())
                        .orderByDesc(Department::getOrderNum));
        List<DepartmentQuery> vos = list.stream().map(p -> {
            DepartmentQuery vop = new DepartmentQuery();
            vop.setId(p.getId());
            vop.setLabel(p.getDepartmentName());
            getChildren(vop);
            return vop;
        }).collect(Collectors.toList());
        query.setChildren(vos);
    }


    /**
     * 根据角色id获取权限
     * @return
     */
    @Override
    public List<DepartmentQuery> selectSonDepartmentId() {
        //先获取根目录
        List<Department> list = baseMapper.selectList(
                Wrappers.<Department>lambdaQuery()
                        .eq(Department::getIsDel, StatusEnum.STATUS_NO.getCode())
                        .eq(Department::getParentId, 0)
                        .eq(Department::getStatus, StatusEnum.STATUS_YES.getCode())
                        .orderByDesc(Department::getOrderNum));
        //获取子菜单
        List<DepartmentQuery> vos = list.stream().map(po -> {
            DepartmentQuery voe = new DepartmentQuery();
            voe.setId(po.getId());
            voe.setLabel(po.getDepartmentName());
            getChildren(voe);
            return voe;
        }).collect(Collectors.toList());
        return vos;
    }

    @Override
    public List<DepartmentVO> selectList(DepartmentRequest request) {
        LambdaQueryWrapper<Department> wrapper = Wrappers.lambdaQuery();
        wrapper.ge(Department::getParentId, 1);
        wrapper.like(StringUtils.isNotEmpty(request.getDepartmentName()), Department::getDepartmentName, request.getDepartmentName());
        wrapper.eq(request.getStatus() != null, Department::getStatus, request.getStatus());
        wrapper.ge(StringUtils.isNotEmpty(request.getStartTimeAdd()), Department::getCreateTime, request.getStartTimeAdd());
        wrapper.le(StringUtils.isNotEmpty(request.getEndTimeAdd()), Department::getCreateTime, request.getEndTimeAdd());
        wrapper.ge(StringUtils.isNotEmpty(request.getStartTimeUp()), Department::getUpdateTime, request.getStartTimeUp());
        wrapper.le(StringUtils.isNotEmpty(request.getEndTimeUp()), Department::getUpdateTime, request.getEndTimeUp());
        wrapper.eq(Department::getIsDel, 0);
        wrapper.orderByDesc(Department::getOrderNum);
        wrapper.orderByDesc(Department::getUpdateTime);
        List<Department> department = departmentMapper.selectList(wrapper);
        //获取所有父级名称
        for (Department dep : department){
            if(dep.getParentId() > 0){
                LambdaQueryWrapper<Department> wrapper2 = Wrappers.lambdaQuery();
                wrapper2.eq(Department::getId,dep.getParentId());
                Department parentDep = departmentMapper.selectOne(wrapper2);
                dep.setParentDepartmentName(parentDep.getDepartmentName());
            }
            if(dep.getParentId() == 1){
                dep.setParentId(0L);
            }
        }
        return pos2Vos(department);
    }

    @Override
    public List<Department> selectDepartmentList(DepartmentVO vo) {
        //获取根目录
        List<Department> pos = baseMapper.selectList(
                Wrappers.<Department>lambdaQuery()
                        .like(StringUtils.isNotEmpty(vo.getDepartmentName()), Department::getDepartmentName, vo.getDepartmentName())
                        .eq(vo.getStatus() != null, Department::getStatus, vo.getStatus())
                        .ge(StringUtils.isNotEmpty(vo.getStartTimeAdd()), Department::getCreateTime, vo.getStartTimeAdd())
                        .le(StringUtils.isNotEmpty(vo.getEndTimeAdd()), Department::getCreateTime, vo.getEndTimeAdd())
                        .ge(StringUtils.isNotEmpty(vo.getStartTimeUp()), Department::getUpdateTime, vo.getStartTimeUp())
                        .le(StringUtils.isNotEmpty(vo.getEndTimeUp()), Department::getUpdateTime, vo.getEndTimeUp())
                        .eq(Department::getIsDel, 0)
                        .orderByDesc(Department::getOrderNum, Department::getUpdateTime)
        );
        ExceptionEnum.FAIL_PRIOR_NULL.doThrowIf(pos == null || pos.size() == 0);
        return pos;
    }

    @Override
    public String selectParentList(Long id) {
        StringBuilder sb = new StringBuilder();
        //获取无线上级部门
        List<DepartmentTemp> list = departmentMapper.selectParentDeps(id);
        list.stream().forEach(d->{
            sb.append(d.getDepartmentName());
            //不为最后低级部门继续添加 ->
            if(list.indexOf(d)!=list.size()-1) {
                sb.append("->");
            }
        });
        return sb.toString();
    }

    /**
     * po->vo
     *
     * @param p
     * @return
     */
    private DepartmentVO po2Vo(Department p) {
        DepartmentVO vo = null;
        {
            try {
                vo = p.clone(DepartmentVO.class);
            } catch (Exception e) {
                ExceptionEnum.FAIL_CHANGE.newException();
            }
        }
        return vo;
    }

    /**
     * po->qo
     * @param department
     * @return
     */
    private DepartmentQuery po2Qo(Department department){
        DepartmentQuery query = null;
        {
            try {
                query = department.clone(DepartmentQuery.class);
            } catch (Exception e){
                ExceptionEnum.FAIL_CHANGE.newException();
            }
        }
        return query;
    }

    /**
     * 对象转换 po->dto
     *
     * @param po
     * @return
     */
    private DepartmentDTO po2Dto(Department po) {
        DepartmentDTO r = null;
        try {
            r = po.clone(DepartmentDTO.class);
        } catch (Exception e) {
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return r;
    }

    /**
     * 对象转换 dto->do
     *
     * @param vo
     * @return
     */
    private Department dto2Po(DepartmentDTO vo) {
        Department r = null;
        try {
            r = vo.clone(Department.class);
        } catch (Exception e) {
            ExceptionEnum.FAIL_CHANGE.newException();
        }
        return r;
    }

    /**
     * 部门DO对象转换 do->vo
     *
     * @param departments 部门do集合
     * @return 部门VO集合
     */
    private List<DepartmentVO> pos2Vos(List<Department> departments) {
        List<DepartmentVO> pos = departments.stream().map(p -> {
            DepartmentVO vo = null;
            try {
                vo = p.clone(DepartmentVO.class);
            } catch (Exception e) {
                ExceptionEnum.FAIL_CHANGE.newException();
            }
            return vo;
        }).collect(Collectors.toList());
        return pos;
    }
}
